package com.eg366.nioLearn.baseSocket.chapter05;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

/**
 * 非阻塞式TCP客户端
 */
public class TcpEchoClientNonBlocking {
	public static void main(String[] args) throws IOException {
		String server = "127.0.0.1";
		int serverPort = 1122;
		byte[] argument = "abcdefghijklmnopqrstuvwxyz".getBytes();

		/* 创建通道，并设为非阻塞 */
		SocketChannel clntChan = SocketChannel.open();
		clntChan.configureBlocking(false);

		/* 返回true：成功建立连接；false：使用非阻塞模式且连接正在创建中 */
		if (!clntChan.connect(new InetSocketAddress(server, serverPort))) {
			/* 非阻塞式，可能在成功建立连接之前即得到返回，false。此时如果试图发送数据会抛异常。所以此处通过finishConnect进行轮询连接状态 */
			while (!clntChan.finishConnect()) {
				System.out.print(".");
			}
		}

		/* 要发起请求输出的字节缓冲 */
		ByteBuffer writeBuf = ByteBuffer.wrap(argument);
		ByteBuffer readBuf = ByteBuffer.allocate(argument.length);	// [pos=0 lim=argument.length cap=argument.length]

		/* 已接受的回显字节长度 */
		int totalBytesRcvd = 0;
		/* 每次接收的字节 */
		int bytesRcvd;
		while (totalBytesRcvd < argument.length) {
			/* 判断当前位置position和limit之间是否有元素，判断position是否小于limit */
			if (writeBuf.hasRemaining()) {
				clntChan.write(writeBuf);
			}
			/* read方法的调用不会阻塞等待，但当没有数据可读时该方法将返回0 */
			if ((bytesRcvd = clntChan.read(readBuf)) == -1) {
				throw new SocketException("Connection closed prematurely");
			}
			totalBytesRcvd += bytesRcvd;
			System.out.print(".");
		}
		System.out.println("received:" + new String(readBuf.array(), 0, totalBytesRcvd));
		clntChan.close();
	}
}
